1 module lib.cmake;
2 
3 import std.file : getcwd, mkdirRecurse;
4 import std.path : buildPath, absolutePath;
5 import std.process : environment;
6 import std..string : indexOf;
7 import std.regex : ctRegex, matchFirst;
8 
9 import lib.set_compiler;
10 import lib.process : executeAt;
11 
12 /** The options used for CMake */
13 struct CmakeOptions
14 {
15   /** The build config. Defaults to `"release"` */
16   string buildConfig = "release";
17   /** The generator to use. Defaults to `"Ninja"` */
18   auto generator = "Ninja";
19   /** The compiler to use. If `CC` and `CXX` environment variables are not specified, it defaults to `clang` */
20   auto compiler = "clang";
21 }
22 
23 /**
24   Configure and build a Cmake project at the given paths.
25 
26   Params:
27       rootDir = The root path which includes CMakeLists.txt
28       buildDir = The building directory path
29       options = The options used for CMake
30 
31 */
32 void cmake(string rootDir = getcwd(), string buildDir = buildPath(getcwd(),
33     "./build"), CmakeOptions options = CmakeOptions())
34 {
35   // build dir
36   mkdirRecurse(buildDir);
37 
38   // env variables
39   string[string] env = set_compiler(options.compiler);
40 
41   // sanitizer
42   const sanitizerArgs = convert_sanitizer(options.buildConfig);
43 
44   // configure
45   executeAt(["cmake", "-G", options.generator, "-S", rootDir, "-B",
46       buildDir] ~ sanitizerArgs, rootDir, env);
47   // build
48   executeAt([
49       "cmake", "--build", buildDir, "--config",
50       convert_build_config(options.buildConfig)
51       ], rootDir, env);
52 }
53 
54 /** Convert D config to Cmake config */
55 private auto convert_build_config(string buildConfig)
56 {
57   if (buildConfig.indexOf("debug") != -1)
58   {
59     return "Debug";
60   }
61   else if (buildConfig.indexOf("release") != -1)
62   {
63     return "Release";
64   }
65 
66   return "Debug";
67 }
68 
69 private auto convert_sanitizer(string buildConfig)
70 {
71   // extract the name of the sanitizer from the build config and store it in the SANITIZER env variable for CMake to use.
72   auto sanitizeMatch = matchFirst(buildConfig, ctRegex!(r"sanitize-(\w*)"));
73   if (!sanitizeMatch.empty() && sanitizeMatch.length == 2)
74   {
75     return ["-D", "CMAKE_SANITIZER=" ~ sanitizeMatch[1]];
76   }
77 
78   return [];
79 }